#include "ggebuf.h"


ggebuf::ggebuf(unsigned int L, unsigned short flag ,unsigned int len)
{
	m_L = (lua_State *)L;
	m_flag = flag;
	m_buflen = len;
	m_bodylen = len-sizeof(GGEHeader);
	m_data = new unsigned char[len];
	m_head = (GGEHeader*)m_data;
	m_wint = (int*)(m_data+sizeof(GGEHeader));
	m_rint = (int*)m_data;
	m_code = NULL;
}
ggebuf::~ggebuf(void)
{
	delete m_data;
}
void ggebuf::Reset(){
	m_i = 0;
	m_len = sizeof(GGEHeader);
	m_lock = false;
}
bool ggebuf::AddNumber(int v){
	if (m_len+sizeof(int)<m_bodylen && !m_lock)
	{
		m_wint[m_i++] = v;
		m_len+=sizeof(int);
		return true;
	}
	return false;
}
bool ggebuf::AddString(LuaString v){
	if (m_len+v.len<m_bodylen && !m_lock)
	{
		memcpy(m_data+m_len,v.str,v.len);
		m_len+=v.len;
		m_lock = true;
		return true;
	}
	return false;
}
void ggebuf::Finish(){
	m_head->flag = m_flag;
	m_head->qty = m_i;
	m_head->len = m_len-sizeof(GGEHeader);
	m_lock = true;
	if (m_code)
	{
		unsigned char* data = m_data+sizeof(GGEHeader);
		int k=0;
		for (int i=0;i<m_len-sizeof(GGEHeader);i++)
		{
			data[i] ^= m_code[k++];
			if (k=m_codelen)
			{
				k=0;
			}
		}
	}
}
unsigned int ggebuf::GetHeaderLen(){
	return sizeof(GGEHeader);
}
unsigned int ggebuf::CheckHeader(){
	if (m_head->flag=m_flag && m_head->len<m_bodylen)
	{
		m_len = m_head->len;
		m_qty = m_head->qty;//bug
		return m_len;
	}
	return 0;
}
LuaTable ggebuf::GetData(){
	LuaTable r(m_L);
	int stroff = m_qty*sizeof(int);
	if (stroff<m_bodylen)
	{
		if (m_code)
		{
			unsigned char* data = m_data;
			int k=0;
			for (int i=0;i<m_len;i++)
			{
				data[i] ^= m_code[k++];
				if (k=m_codelen)
				{
					k=0;
				}
			}
		}
		int i;
		for (i=0;i<m_qty;i++)
		{
			r.set(i+1,m_rint[i]);
		}
		if (m_len-stroff>0)
		{
			LuaString data;
			data.len = m_len-stroff;
			data.str = (const char *)m_data+stroff;
			r.set(i+1,data);
		}

	}

	return r;
}
unsigned int ggebuf::GetPtr(){
	return (unsigned int)m_data;
}
unsigned int ggebuf::GetLen(){
	return m_len;
}
void ggebuf::SetCode(char* psd,int len){
	m_code = (unsigned char*)psd;
	m_codelen = len;
}
void ggebuf::SetComp(bool v){
	m_comp = v;
}
int REG_GGEBUF(lua_State* L){
	ELuna::registerClass<ggebuf>(L, "__ggebuf", ELuna::constructor<ggebuf,unsigned int , unsigned short  ,unsigned int>);
	ELuna::registerMethod<ggebuf>(L, "Reset", &ggebuf::Reset);
	ELuna::registerMethod<ggebuf>(L, "AddNumber", &ggebuf::AddNumber);
	ELuna::registerMethod<ggebuf>(L, "AddString", &ggebuf::AddString);
	ELuna::registerMethod<ggebuf>(L, "Finish", &ggebuf::Finish);
	ELuna::registerMethod<ggebuf>(L, "GetHeaderLen", &ggebuf::GetHeaderLen);
	ELuna::registerMethod<ggebuf>(L, "CheckHeader", &ggebuf::CheckHeader);
	ELuna::registerMethod<ggebuf>(L, "GetData", &ggebuf::GetData);
	ELuna::registerMethod<ggebuf>(L, "GetPtr", &ggebuf::GetPtr);
	ELuna::registerMethod<ggebuf>(L, "GetLen", &ggebuf::GetLen);
	ELuna::registerMethod<ggebuf>(L, "SetCode", &ggebuf::SetCode);
	return 1;
}